package com.hack4jp.hackearthquakes;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Locale;

import org.json.JSONException;

import com.google.android.maps.GeoPoint;

import twitter4j.StatusUpdate;
import twitter4j.TwitterException;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.provider.MediaStore;
import android.text.SpannableStringBuilder;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager.LayoutParams;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TableLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;

public class HackEarthquakes extends Activity implements LocationListener,
		Runnable {

	public final static String PREF_AutoLocation = "AutoLocation",
			PREF_CurrentLocationLatitude = "CurrentLocationLatitude",
			PREF_CurrentLocationLongitude = "CurrentLocationLongitude";

	private static final int MENU_PREFERENCES = 0, MENU_TIMELINE = 1;

	private static final int THREAD_SUCCEED = 0, EXCEPT_GENERIC = 1,
			EXCEPT_TWITTER = 2;

	private static final int REQUEST_OAUTH = 1, REQUEST_MAP = 2,
			REQUEST_CAMERA = 3;

	public static final String HASHTAG = "#hackearthquakes";

	private LocationManager _locationManager;
	private boolean _autoLocation = false;
	private double _latitude = 0.0;
	private double _longitude = 0.0;
	private String _strTweet = null;
	private Bitmap _imgBitmap = null;

	private DetectableSoftKeyLayout _layoutDetectable = null;
	private TableLayout _layoutTable = null;
	private Button _buttonStartCamera = null;
	private Button _buttonTweetAndUpload = null;
	private Button _buttonSetLocation = null;
	private EditText _editTweet = null;
	private ImageView _imageCamera = null;
	private CheckBox _checkboxAutoSetLocation = null;
	private TextView _txtLocation = null;

	private static ProgressDialog _dialogStatus = null;
	private Thread _threadUpload = null;
	private TwitterObject twt = null;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		// ソフトウェアキーボードを非表示にする。
		this.getWindow().setSoftInputMode(
				LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);

		Preferences.setContext(this.getApplicationContext());

		// 保存されている設定値の読み込み
		SharedPreferences sp = PreferenceManager
				.getDefaultSharedPreferences(this);
		_autoLocation = sp.getBoolean(PREF_AutoLocation, true);
		String strLatitude = sp.getString(PREF_CurrentLocationLatitude, "0.0");
		String strLongitude = sp.getString(PREF_CurrentLocationLongitude, "0.0");
		_latitude = Double.parseDouble(strLatitude);
		_longitude = Double.parseDouble(strLongitude);

		twt = new TwitterObject();

		initializeViews();
		initializeLocationManage();
		setCurrentLocationText();
	}

	DetectableSoftKeyLayout.OnSoftKeyShownListener _listnerSoftKey = new DetectableSoftKeyLayout.OnSoftKeyShownListener() {
		@Override
		public void onSoftKeyShown(boolean isShown) {
			if (isShown) {
				// レイアウト非表示
				_layoutTable.setVisibility(View.GONE);
				_buttonTweetAndUpload.setVisibility(View.GONE);
			} else {
				// レイアウト表示
				_layoutTable.setVisibility(View.VISIBLE);
				_buttonTweetAndUpload.setVisibility(View.VISIBLE);
			}
		}
	};

	private void initializeViews() {
		setContentView(R.layout.main);

		_layoutDetectable = (DetectableSoftKeyLayout) findViewById(R.id.layoutDetectable);
		_layoutTable = (TableLayout) findViewById(R.id.tableButtons);

		_buttonStartCamera = (Button) findViewById(R.id.buttonStartCamera);
		_buttonStartCamera.setOnClickListener(onClickStartCameraListener);

		_buttonTweetAndUpload = (Button) findViewById(R.id.buttonTweetAndUpload);
		_buttonTweetAndUpload.setOnClickListener(onClickTweetAndUploadListener);

		_buttonSetLocation = (Button) findViewById(R.id.buttonSetLocation);
		_buttonSetLocation.setOnClickListener(onClickSetLocationListener);
		_txtLocation = (TextView) findViewById(R.id.currentLocation);
		_txtLocation = (TextView) findViewById(R.id.currentLocation);

		_checkboxAutoSetLocation = (CheckBox) findViewById(R.id.checkBoxAutoSetLocation);
		_checkboxAutoSetLocation
				.setOnClickListener(onClickAutoSetLocationListener);
		if (_checkboxAutoSetLocation != null)
			_checkboxAutoSetLocation.setChecked(_autoLocation);

		_imageCamera = (ImageView) findViewById(R.id.imageCamera);
		_editTweet = (EditText) findViewById(R.id.editTweet);

		showCameraImage();

		_layoutDetectable.setListener(_listnerSoftKey);
	}

	private void initializeLocationManage() {
		_locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
		if (_latitude == 0.0 || _longitude == 0.0) {
			Location lastLocation = _locationManager
				.getLastKnownLocation(LocationManager.GPS_PROVIDER);
			if (lastLocation != null) {
				// 最後の現在地をセット
				_latitude = lastLocation.getLatitude();
				_longitude = lastLocation.getLongitude();
				setCurrentLocationText();
				saveLocation();
			}
		}
	}

	private void updateLocation() {
		if (_locationManager != null) {
			if (_autoLocation)
				_locationManager.requestLocationUpdates(
						LocationManager.GPS_PROVIDER, 0, 0, this);
			else
				_locationManager.removeUpdates(this);
		}
	}

	public void setCurrentLocationText() {
		if (_txtLocation == null)
			return;

		try {
			Geocoder geocoder = new Geocoder(this, Locale.JAPAN);
			GeoPoint gp = LocationMapActivity
					.getGeoPoint(_latitude, _longitude);

			List<Address> list_address = geocoder.getFromLocation(
					LocationMapActivity.getGeocoderDouble(gp.getLatitudeE6()),
					LocationMapActivity.getGeocoderDouble(gp.getLongitudeE6()),
					1);
			if (!list_address.isEmpty()) {
				Address address = list_address.get(0);
				StringBuffer sbAddress = new StringBuffer();

				int count = 0;
				while (true) {
					String addr = address.getAddressLine(count++);
					if (addr == null)
						break;

					if (sbAddress.length() == 0) {
						if (addr.equals("日本") || addr.equals("Japan"))
							continue;
					}

					if (sbAddress.length() > 0)
						sbAddress.append(" ");

					sbAddress.append(addr);
				}

				_txtLocation.setText(sbAddress.toString());
			}
		} catch (Exception ex) {
			_txtLocation.setText("");
		}
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		super.onCreateOptionsMenu(menu);

		MenuItem itemSetting = menu.add(Menu.NONE, MENU_PREFERENCES, Menu.NONE,
				getString(R.string.menu_setting));
		itemSetting.setIcon(android.R.drawable.ic_menu_preferences);

		MenuItem itemTimeline = menu.add(Menu.NONE, MENU_TIMELINE, Menu.NONE,
				getString(R.string.menu_timeline));
		itemTimeline.setIcon(android.R.drawable.ic_menu_agenda);

		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {

		Intent nextIntent = null;

		switch (item.getItemId()) {
		case MENU_PREFERENCES:
			nextIntent = new Intent(HackEarthquakes.this,
					PreferencesActivity.class);
			break;
		case MENU_TIMELINE:
			nextIntent = new Intent(HackEarthquakes.this,
					TwitterTimelineActivity.class);
			break;
		}

		if (nextIntent != null)
			startActivity(nextIntent);

		return true;
	}

	private void saveAutoLocation() {
		SharedPreferences sp = PreferenceManager
				.getDefaultSharedPreferences(this);
		Editor ed = sp.edit();
		ed.putBoolean(PREF_AutoLocation, _autoLocation);
		ed.commit();
	}

	private void saveLocation() {
		SharedPreferences sp = PreferenceManager
				.getDefaultSharedPreferences(this);
		Editor ed = sp.edit();
		ed.putString(PREF_CurrentLocationLatitude, Double.valueOf(_latitude)
				.toString());
		ed.putString(PREF_CurrentLocationLongitude, Double.valueOf(_longitude)
				.toString());
		ed.commit();
	}

	private View.OnClickListener onClickStartCameraListener = new View.OnClickListener() {
		@Override
		public void onClick(View v) {
			Log.v("HackEarthquake.onClickStartCameraListener", "onClick");
			showCameraView();
		}
	};

	private View.OnClickListener onClickTweetAndUploadListener = new View.OnClickListener() {
		@Override
		public void onClick(View v) {
			Log.v("HackEarthquake.onClickTweetAndUploadListener", "onClick");

			String tempImagePath = FileManager.getTempImagePath();
			File imgFile = new File(tempImagePath);
			if (!imgFile.exists()) {
				String msg = getString(R.string.alerttakepicture);
				showAlert(msg, null, null, null);
				return;
			}
			
			SpannableStringBuilder sb = (SpannableStringBuilder) _editTweet
					.getText();
			_strTweet = sb.toString();
			if (_strTweet.length() == 0) {
				String msg = getString(R.string.tweethint);
				showAlert(msg, null, null, null);
				return;
			}

			if (_latitude == 0.0 || _longitude == 0.0) {
				String msg = getString(R.string.nolocation);
				showAlert(msg, null, null, null);
				return;
			}

			DialogInterface.OnClickListener onOK = new DialogInterface.OnClickListener() {
				@Override
				public void onClick(DialogInterface dialog, int which) {
					startUpload();
				}
			};

			DialogInterface.OnClickListener onCancel = new DialogInterface.OnClickListener() {
				@Override
				public void onClick(DialogInterface dialog, int which) {
					String msg = getString(R.string.uploadcancel);
					showAlert(msg, null, null, null);
				}
			};

			String msgQuestion = getString(R.string.beforetweet);
			showAlert(msgQuestion, null, onOK, onCancel);
		}
	};

	private View.OnClickListener onClickSetLocationListener = new View.OnClickListener() {
		@Override
		public void onClick(View v) {
			Log.v("HackEarthquakes.onClickSetLocationListener", "onClick");
			showMapView();
		}
	};

	private View.OnClickListener onClickAutoSetLocationListener = new View.OnClickListener() {
		@Override
		public void onClick(View v) {
			Log.v("HackEarthquakes.onClickAutoSetLocationListener", "onClick");
			_autoLocation = _checkboxAutoSetLocation.isChecked();
			saveAutoLocation();
			updateLocation();
		}
	};

	private void showAlert(String message, String caption,
			DialogInterface.OnClickListener onOK,
			DialogInterface.OnClickListener onCancel) {
		AlertDialog.Builder ab = new AlertDialog.Builder(this);

		if (caption != null)
			ab.setTitle(caption);

		ab.setMessage(message);

		ab.setPositiveButton("OK", onOK);

		if (onCancel != null) {
			ab.setNegativeButton("Cancel", onCancel);
		}

		AlertDialog alertDialog = ab.create();
		alertDialog.show();
	}

	private void showStatusDialog(String message) {
		if (_dialogStatus == null)
			_dialogStatus = new ProgressDialog(this);

		_dialogStatus.setMessage(message);
		_dialogStatus.setProgressStyle(ProgressDialog.STYLE_SPINNER);
		_dialogStatus.show();
	}

	private void hideStatusDialog() {
		if (_dialogStatus == null)
			return;

		_dialogStatus.dismiss();
		_dialogStatus = null;
	}

	private void showCameraView() {
		// Intent intent = new Intent(HackEarthquake.this,
		// CameraActivity.class);
		// this.startActivityForResult(intent, REQUEST_CAMERA);

		File tmpFile = new File(FileManager.getTempImagePath());
		Intent intent = new Intent();
		intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
		intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(tmpFile));
		startActivityForResult(intent, REQUEST_CAMERA);
	}

	private void showCameraImage() {
		String tempImagePath = FileManager.getTempImagePath();
		File imgFile = new File(tempImagePath);
		if (imgFile.exists()) {
			int MAX_IMAGE_SIZE = 200;

			BitmapFactory.Options opt = new BitmapFactory.Options();
			opt.inJustDecodeBounds = true;
			BitmapFactory.decodeFile(imgFile.getAbsolutePath(), opt);

			int scaleW = opt.outWidth / MAX_IMAGE_SIZE;
			int scaleH = opt.outHeight / MAX_IMAGE_SIZE;
			opt.inSampleSize = Math.max(scaleW, scaleH);

			if (_imgBitmap != null) {
				_imgBitmap.recycle();
				_imgBitmap = null;
			}

			opt.inJustDecodeBounds = false;
			_imgBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath(),
					opt);
			_imageCamera.setImageBitmap(_imgBitmap);
		}
	}

	private void showMapView() {
		_autoLocation = false;
		_checkboxAutoSetLocation.setChecked(_autoLocation);
		saveAutoLocation();
		updateLocation();

		Intent intent = new Intent(this, LocationMapActivity.class);
		intent.putExtra("latitude", _latitude);
		intent.putExtra("longitude", _longitude);
		this.startActivityForResult(intent, REQUEST_MAP);
		return;
	}

	private void startUpload() {
		try {
			if (!twt.tokenAvailable()) {
				Intent intent = new Intent(this, TwitterLogin.class);
				this.startActivityForResult(intent, REQUEST_OAUTH);
				return;
			}
		} catch (Exception e) {
			Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
			return;
		}

		startUploadThread();
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode,
			Intent intent) {
		if (requestCode == REQUEST_OAUTH) {
			if (resultCode == RESULT_OK) {
				try {
					startUploadThread();
				} catch (Exception e) {
					Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
				}
			} else if(resultCode == RESULT_CANCELED){	
				String msg = getString(R.string.autherror);
				showAlert(msg, null, null, null);
			}
		}

		if (requestCode == REQUEST_MAP && resultCode == RESULT_OK) {
			_latitude = intent.getDoubleExtra("latitude", 0.0);
			_longitude = intent.getDoubleExtra("longitude", 0.0);
			setCurrentLocationText();
			saveLocation();
		}

		if (requestCode == REQUEST_CAMERA && resultCode == RESULT_OK) {
			showCameraImage();
		}
	}

	private void startUploadThread() {
		String msg = getString(R.string.uploading);
		showStatusDialog(msg);

		_threadUpload = new Thread(this);
		_threadUpload.start();
	}

	private Handler handler = new Handler() {
		public void handleMessage(Message msg) {
			if (msg.what == THREAD_SUCCEED) {
				String showMsg = getString(R.string.uploaded);
				showAlert(showMsg, null, null, null);
			} else if (msg.what == EXCEPT_TWITTER) {
				showAlert((String) msg.obj, null, null, null);
			} else {
	    		String strMsg = (String)msg.obj;
	    		String strAlert = getString(R.string.alertcheckconnection);
	    		showAlert(strAlert + "\n" + strMsg, null, null, null);		
			}
			hideStatusDialog();
		}
	};

	@Override
	public void run() {
		Message msg = new Message();
		try {
			tweet();
			msg.what = THREAD_SUCCEED;
			msg.obj = "";
		} catch (InterruptedException e) {
			// 無視
		} catch (TwitterException e) {
			msg.what = EXCEPT_TWITTER;
			msg.obj = e.getErrorMessage();
		} catch (Exception e) {
			msg.what = EXCEPT_GENERIC;
			msg.obj = e.getMessage();
		}

		handler.sendMessage(msg);
	}

	protected void tweet() throws Exception, JSONException, IOException {
		if (_strTweet == null)
			return;

		twt.createLocation(_latitude, _longitude);
		if (!twt.twitterAvailable()) {
			twt.createFactory();
		}

		String tempImagePath = FileManager.getTempImagePath();
		File imgFile = new File(tempImagePath);

		TwitpicUpload twitpic = twt.getTwitpicUploadObject();
		String url = twitpic.upload(imgFile, "");
		if (url == null) {
			throw new Exception("twitpic upload error");
		}

		// long now = System.currentTimeMillis();
		// Date dateNow = new Date(now);
		// SimpleDateFormat simpleDateFormat = new
		// SimpleDateFormat("yyyy/MM/dd HH:mm:ss");

		StatusUpdate status = new StatusUpdate(
		// simpleDateFormat.format(dateNow) +
				_strTweet + " " + url + " " + HackEarthquakes.HASHTAG);
		status.setLocation(twt.getLocation());

		twt.getTwitter().updateStatus(status);
	}

	@Override
	protected void onResume() {
		updateLocation();

		super.onResume();
	}

	@Override
	protected void onPause() {
		if (_locationManager != null) {
			_locationManager.removeUpdates(this);
		}
		super.onPause();
	}

	@Override
	public void onLocationChanged(Location location) {
		if (_autoLocation) {
			double newLatitude = location.getLatitude();
			double newLongitude = location.getLongitude();
			if (newLatitude != _latitude || newLongitude != _longitude) {
				_latitude = newLatitude;
				_longitude = newLongitude;
				setCurrentLocationText();
				saveLocation();
			}
		}
	}

	@Override
	public void onStatusChanged(String provider, int status, Bundle extras) {
	}

	@Override
	public void onProviderEnabled(String provider) {
	}

	@Override
	public void onProviderDisabled(String provider) {
	}
}